package com.itheima.stock.sharding;


import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;


/**
 * @author: siwukun
 * @date: 2022/06/13
 * @description:
 */
public class CommonShardingAlgorithm4Tb implements PreciseShardingAlgorithm<Date>, RangeShardingAlgorithm<Date> {

    /**
     * 精准策略
     *
     * @param tbNames              分表名称集合
     * @param preciseShardingValue 分片键数据的封装
     * @return 返回具体某一张物理表
     */
    @Override
    public String doSharding(Collection<String> tbNames, PreciseShardingValue<Date> preciseShardingValue) {

        //获取片键值
        final Date value = preciseShardingValue.getValue();
        //将value转换成字符串
        final String yyyyMM = new DateTime(value).toString(DateTimeFormat.forPattern("yyyyMM"));
        //从tbNames获取以yyyyMM结尾的数据源
        final Optional<String> first = tbNames.stream().filter(tbName -> tbName.endsWith(yyyyMM)).findFirst();
        String actul = "";
        //数据如果存在
        if (first.isPresent()) {
            actul = first.get();
        }
        return actul;
    }


    /**
     * 范围策略
     *
     * @param tbNames            分表名称集合
     * @param rangeShardingValue 封装分偏键范围查询的对象
     *                           核心做法：就是将日期比较转化成数字比较
     * @return 返回具体某一张物理表
     */
    @Override
    public Collection<String> doSharding(Collection<String> tbNames, RangeShardingValue<Date> rangeShardingValue) {

        //获取日期值
        final Range<Date> range = rangeShardingValue.getValueRange();
        //判断日期范围是否有下限值
        if (range.hasLowerBound()) {
            //获取日期的下限值
            final Date date = range.lowerEndpoint();
            //将date数据转换成yyyyMM格式的字符串
            final String yyyyMM = new DateTime(date).toString(DateTimeFormat.forPattern("yyyyMM"));
            //核心做法：就是将日期比较转化成数字比较 yyyyMM转成数字进行比较
            final Integer intDate = Integer.parseInt(yyyyMM);
            //从tbNames集合中获取大于等于intDate的表的名称集合
            tbNames = tbNames.stream().filter(tbName -> Integer.parseInt(tbName.substring(tbName.lastIndexOf("_") + 1)) >= intDate).collect(Collectors.toList());
        }
        //判断日期范围是否有上限值
        if (range.hasLowerBound()) {
            //获取日期的下限值
            final Date date = range.upperEndpoint();
            //将date数据转换成yyyyMM格式的字符串
            final String yyyyMM = new DateTime(date).toString(DateTimeFormat.forPattern("yyyyMM"));
            //核心做法：就是将日期比较转化成数字比较 yyyyMM转成数字进行比较
            final Integer intDate = Integer.parseInt(yyyyMM);
            //从tbNames集合中获取大于等于intDate的表的名称集合
            tbNames = tbNames.stream().filter(tbName -> Integer.parseInt(tbName.substring(tbName.lastIndexOf("_") + 1)) <= intDate).collect(Collectors.toList());
        }
        return tbNames;
    }
}
